package cn.wk.controller;

import cn.wk.domain.CourseDoc;
import cn.wk.query.CourseDocQuery;
import cn.wk.repository.CourseDocRepository;
import cn.wk.resultmapping.HighlightResultMapper;
import cn.wk.util.AjaxResult;
import cn.wk.util.PageList;
import cn.wk.vo.AggVo;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping("/courseSearch")
public class CourseDocController {
    /**
     * 课程上架 操作es
     */
    @Autowired
    private CourseDocRepository courseDocRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired  //高亮
    private HighlightResultMapper highlightResultMapper;
    @PostMapping("/addOrUpdate")
    private AjaxResult addOrUpdate(@RequestBody CourseDoc courseDoc){
        System.out.println("------------课程上架-------------");
        courseDocRepository.save(courseDoc);
        return AjaxResult.me().setSuccess(true).setMessage("课程上架成功");
    }

    /**
     * 课程下架操作es
     * @param courseId
     * @return
     */
    @DeleteMapping("/offCourse/{id}")
    private AjaxResult del(@PathVariable("id") Long courseId){
        System.out.println("------------课程下架-------------");
        courseDocRepository.deleteById(courseId);
        return AjaxResult.me().setSuccess(true).setMessage("课程下架成功");
    }

    @PostMapping("/courseDocQuery")
    PageList<CourseDoc> queryCourse(@RequestBody CourseDocQuery courseDocQuery) {
        System.out.println(courseDocQuery);
        //把courseQeury转成ES的查询对象
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //相当于es中bool
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //关键字
        String keyword = courseDocQuery.getKeyword();
        if(StringUtils.isNotBlank(keyword)){
            //关键字查询的字段，这是按照es的格式进行查询的
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", keyword));
        }
        String tenantName = courseDocQuery.getTenantName();
        if(StringUtils.isNotBlank(tenantName)){
            boolQueryBuilder.must(QueryBuilders.matchQuery("tenantName", tenantName));
        }
        String courseTypeName = courseDocQuery.getCourseTypeName();
        if(StringUtils.isNotBlank(courseTypeName)){
            boolQueryBuilder.must(QueryBuilders.matchQuery("courseTypeName", courseTypeName));
        }
        //根据前台传的销量 人气 新品 评论 价格等排序
        //如果没有传的话 就默认按照价格来
        String field = StringUtils.isBlank(courseDocQuery.getSortField())?"price":courseDocQuery.getSortField();
        FieldSortBuilder sortBuilder = new FieldSortBuilder(field);
        //排序类型
        String sortType = courseDocQuery.getSortType();
        SortOrder sortOrder = sortType!=null && sortType.equals(SortOrder.ASC.toString())?SortOrder.ASC:SortOrder.DESC;
        //根据价格区间查询
        Integer max = courseDocQuery.getPriceMax();
        Integer min = courseDocQuery.getPriceMin();
        if(max != null){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(max));
        }
        if(min != null){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(min));
        }
        //聚合查询 要显示机构和分类
        builder.addAggregation(AggregationBuilders.terms("tenantNameAgg").field("tenantName").order(Terms.Order.count(false)));
        builder.addAggregation(AggregationBuilders.terms("couseTypeAgg").field("courseTypeName").order(Terms.Order.count(false)));
        //高亮
        HighlightBuilder.Field highlightBuilder = new HighlightBuilder.Field("name").preTags("<font style='color:red'><b>").postTags("</b></font>");
        builder.withHighlightFields(highlightBuilder);
        //分页
        PageRequest pageRequest = PageRequest.of(courseDocQuery.getPage()-1, courseDocQuery.getRows());
        //向build中加入排序
        builder.withSort(sortBuilder.order(sortOrder));
        //向build中加入查询
        builder.withQuery(boolQueryBuilder);
        //向build中加入分页
        builder.withPageable(pageRequest);
        //Page<CourseDoc> docPage = courseDocRepository.search(builder.build());
        AggregatedPage<CourseDoc> docPage = elasticsearchTemplate.queryForPage(builder.build(), CourseDoc.class,highlightResultMapper);
        //根据名字获取聚合查询的结果
        StringTerms tenantNameAgg = (StringTerms)docPage.getAggregation("tenantNameAgg");
        //用集合装数据
        ArrayList<AggVo> tenantNameList = new ArrayList<>();
        //用map装集合中的数据 因为是多个list
        HashMap<String, List<AggVo>> map = new HashMap<>();
        //获取数据
        List<StringTerms.Bucket> buckets = tenantNameAgg.getBuckets();
        //遍历装数据
        buckets.stream().forEach(tn->{
            AggVo aggVo = new AggVo();
            aggVo.setKey(tn.getKeyAsString());
            aggVo.setCount(tn.getDocCount());
            tenantNameList.add(aggVo);
        });
        //保存到map
        map.put("tenantNameAgg",tenantNameList);
        //根据名字获取聚合查询的结果
        StringTerms couseTypeN = (StringTerms)docPage.getAggregation("couseTypeAgg");
        //新建一个list
        ArrayList<AggVo> couseTypeName = new ArrayList<>();
        //获取数据
        List<StringTerms.Bucket> cbuckets = couseTypeN.getBuckets();
        //遍历装数据
        cbuckets.stream().forEach(cn->{
            AggVo aggVo = new AggVo();
            aggVo.setKey(cn.getKeyAsString());
            aggVo.setCount(cn.getDocCount());
            couseTypeName.add(aggVo);
        });
        //保存到map
        map.put("couseTypeAgg",couseTypeName);
        PageList<CourseDoc> pageList = new PageList<>(docPage.getTotalPages(), docPage.getContent(),map);
        return pageList;
    }
}
